class MyPromise {
  constructor(executor) {
    this.PromiseState = 'pending'
    this.PromiseResult = null
    // 保存成功的回调，解决定时器延时开启resolve，如果有定时器，在状态为pending
    // 时，将成功和失败的回调加入到这个数组中保存起来，当执行了resolve或者reject时
    // 在来执行这个回调
    this.onResolveCallbacks = []
    // 保存失败的回调
    this.onRejectCallbacks = []
    // 初始化方法
    this.initBind()
    // Promise中有throw的话，就相当于执行了reject
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      // 收到错误，将状态改为拒绝并且会抛出一个错误
      this.reject(error)
      throw new Error(error)
    }
  }
  initBind() {
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)
  }
  // 实现resolve
  resolve(value) {
    // 状态只能改一次
    if (this.PromiseState != 'pending') return
    this.PromiseState = 'fulfilled'
    this.PromiseResult = value
    // 只要进入到循环说明，有回调函数待执行,为了解决定时器延迟resolve
    while (this.onResolveCallbacks.length) {
      // 执行最先加入的then方法中的回调
      this.onResolveCallbacks.shift()(this.PromiseResult)
    }
  }
  reject(reason) {
    // 状态只能改一次
    if (this.PromiseState != 'pending') return
    this.PromiseState = 'rejected'
    this.PromiseResult = reason
    // 只要进入到循环说明，有回调函数待执行
    while (this.onRejectCallbacks.length) {
      // 执行最先加入的then方法中的回调
      this.onRejectCallbacks.shift()(this.PromiseResult)
    }
    // 状态变为拒绝，也会抛出一个错误
    // console.error(reason)
  }
  
  // promise链式说明then是一个Promise函数，所以返回Promise函数
  then(onResolve, onReject) {
    // 传入的参数必须是函数，不然会报错
    onResolve = typeof onResolve == 'function' ? onResolve : val => val
    onReject = typeof onReject == 'function' ? onReject : err => { throw (err) }
    //返回一个Promise对象
    var thenPromise = new MyPromise((resolve, reject) => {
      // 封装执行相应成功失败的回调
      const resolvePromise = cb => {
        // 放一个定时器是为了 then是异步操作,所以用一个定时器来代替微任务
        setTimeout(() => {
          try {
            // 得到函数的返回值
            const x = cb(this.PromiseResult)
            if (x === thenPromise) {
              throw new Error('不能返回自己')
            }
            // 如果返回值是一个Promise函数，就执行then
            if (x instanceof MyPromise) {
              // 如果返回值是promise对象，返回值为成功，新promise就是成功
              // 如果返回值是promise对象，返回值为失败，新promise就是失败
              // 谁知道返回的promise是失败成功？只有then知道，这里的then是我们自己的相当于递归，
              x.then(resolve, reject)
            } else {
              // 如果返回的不是promise对象，就返回这个值
              resolve(x)
            }
          } catch (err) {
            reject(err)
            throw new Error(err)
          }
        })
      }
      if (this.PromiseState == 'fulfilled') resolvePromise(onResolve)
      else if (this.PromiseState == 'rejected') resolvePromise(onReject)
      else if (this.PromiseState == 'pending') {
        // 当遇到延时执行resolve和reject时，先将相应的回调函数加入到待执行的数组中，等待执行
        this.onResolveCallbacks.push(resolvePromise.bind(this, onResolve))
        this.onRejectCallbacks.push(resolvePromise.bind(this, onReject))
      }
    })
    return thenPromise
  }
  // 当所有的promises都为成功时才返回成功的状态
  static all(promises) {
    // 存储状态为成功的结果
    const arr = []
    return new MyPromise((resolve, reject) => {
      // 向数组中添加方法
      const addDate = (index, value) => {
        // 不能以这种方式添加元素
        // arr.push(value)
        arr[index] = value
        if (arr.length === promises.length) {
          resolve(arr)
        }
      }
      promises.forEach((item, index) => {
        if (item instanceof MyPromise) {
          // 成功的回调，就给就将成功的结果加入到数组中
          item.then(res => {
            addDate(index, res)
          }, err => {
            reject(err)
          })
        } else {
          // 防止非promise数据不是异步的，因为then开启了定时器，这里也要开启一个以保证微任务
          setTimeout(() => { addDate(index, item) })
        }
      })
    })
  }
  // 返回promises中第一个元素，第一个promise的状态就是整个的状态，如果不是promise就是成功的状态
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise => {
        if (promise instanceof MyPromise) {
          promise.then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        } else {
          // 防止非promise数据不是异步的，不加定时器就会导致如果有不是promise函数，不管第一个是不是这个项，最后都会返回这一项
          setTimeout(() => { resolve(promise) })
        }
      })
    })
  }
  //返回一个对象数组，每一个对象都有status属性和value或者reason，status记录每一个promise的状态，value为成功的返回值
  // reason记录每一个promise的失败的返回值，如果是非promise则返回成功的状态
  static allSettled(promises) {
    return new MyPromise((resolve, reject) => {
      let res = []
      const addData = (status, value, i) => {
        res[i] = status == 'fulfilled' ? {status,value} 
        : {status,reason: value}
        if (res.length === promises.length) {
          //将promises数组的状态值和结果返回
          resolve(res)
        }
      }
      promises.forEach((item, index) => {
        if (item instanceof MyPromise) {
          item.then((res) => {
            addData('fulfilled', res, index)
          }, err => {
            addData('rejected', err, index)
          })
        } else {
          addData('fulfilled', item, index)
        }
      })
    })
  }
}
